package com.acceptable.qucun.file.service.impl;

import com.acceptable.qucun.file.entity.FileInfo;
import com.acceptable.qucun.file.entity.FileShare;
import com.acceptable.qucun.file.entity.ShareInfo;
import com.acceptable.qucun.file.entity.template.FileShareItem;
import com.acceptable.qucun.file.entity.template.TemplateFile;
import com.acceptable.qucun.file.exception.FileOperationException;
import com.acceptable.qucun.file.mapper.FileShareItemMapper;
import com.acceptable.qucun.file.mapper.FileShareMapper;
import com.acceptable.qucun.file.mapper.TemplateFileMapper;
import com.acceptable.qucun.file.service.FileShareService;
import com.acceptable.qucun.generic.exception.GenericExcetion;
import com.acceptable.qucun.generic.util.CodeUtil;
import com.acceptable.qucun.generic.util.RandomUtil;
import com.acceptable.qucun.generic.util.StringFormatUtil;
import com.acceptable.qucun.generic.util.TimeUtil;
import com.acceptable.qucun.generic.util.result.ResultUtil;
import com.acceptable.qucun.generic.util.result.error.FileErrorResult;
import com.acceptable.qucun.generic.util.result.error.GenericErrorResult;
import com.acceptable.qucun.generic.util.result.success.FileSuccessResult;
import com.acceptable.qucun.user.entity.User;
import com.acceptable.qucun.user.entity.UserInfo;
import com.acceptable.qucun.user.mapper.UserMapper;
import com.acceptable.qucun.user.service.impl.UserDatabaseOperation;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 巴斯罗斯·K·赫斯洛利
 * @since 2021-08-29
 */
@Service
public class FileShareServiceImpl extends ServiceImpl<FileShareMapper, FileShare> implements FileShareService {
    @Autowired private FileShareMapper shareMapper;
    @Autowired private TemplateFileMapper fileMapper;
    @Autowired private FileShareItemMapper shareItemMapper;
    @Autowired private UserDatabaseOperation userDatabaseOperation;
    @Autowired private UserMapper userMapper;
    @Autowired private FileDatabaseOperation fileDatabaseOperation;

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED,
            rollbackFor = {Exception.class})
    public Map<String, Object> shareExistedMultiFile(Map<String, String> dataMap){
        Integer userId = Integer.parseInt(dataMap.get("src_user_id"));
        String sharePwd = dataMap.get("share_pwd");
        if (StringFormatUtil.isEmpty(sharePwd))
            sharePwd = RandomUtil.mixNumberLetter(4);
        int day = Integer.parseInt(dataMap.get("life"));

        List<Long> fileIdList = CodeUtil.string2List(dataMap.get("file_id"), Long.class);
        List<TemplateFile> fileList = new ArrayList<>();
        Integer shareId = Integer.parseInt(RandomUtil.fullNumber(8));
        Date date = new Date();
        String url = RandomUtil.shareUrlUnique(20, shareMapper);
        // 构造并插入整个分享项信息
        {
            FileShare share = new FileShare();
            LocalDateTime now = TimeUtil.date2LocalDateTime(date);
            share.setShareId(shareId);
            share.setUserId(userId);
            share.setShareTime(now);
            share.setExpireTime(now.plusDays(day));
            share.setPassword(CodeUtil.base64Encode(sharePwd));
            share.setUrl(url);
            shareMapper.insert(share);
        }

        // 构造并更新的分享子项信息以及文件信息
        {
            List<FileShareItem> shareItemList = new ArrayList<>();
            for (Long fileId: fileIdList){
                TemplateFile file = fileMapper.selectByFileId(userId, fileId);
                fileList.add(file);

                FileShareItem item = new FileShareItem();
                item.setFileId(fileId);
                item.setShareId(shareId);
                item.setShareItemId(RandomUtil.shareItemIdUnique(13, userId, shareItemMapper));
                shareItemList.add(item);
            }
            shareItemMapper.insertBatch(userId, shareItemList);
            fileMapper.updateBatchByFileId(userId, fileList);
        }

        Map<String, Object> resMap =new HashMap<>();
        resMap.put("code", FileSuccessResult.SHARE_CREATE_LINK_SUCCESS.getCode());
        resMap.put("password", sharePwd);
        resMap.put("url", url);
        return resMap; 
    }

    /**
     *  获取分享人以及分享信息
     *  不存在/过期 抛异常
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Map<String, Object> shareInfo(String url,
                                         boolean getFileList){
        FileShare share = shareMapper.selectByUrl(url);
        if (share == null)
            throw new FileOperationException(FileErrorResult.SHARE_NOT_EXIST_ERROR);

        User user = userMapper.selectByUserId(share.getUserId());
        if (user == null || user.getDeleted())
            throw new FileOperationException(FileErrorResult.SHARE_NOT_EXIST_ERROR);

        // 过期处理 此处不删除 由分享者进行相关操作
        Date now = new Date();
        Date expireTime = TimeUtil.localDateTime2Date(share.getExpireTime());
        // 原主人在查看时会获取分享文件列表 获取者查看时不获取
        if (!getFileList && now.after(expireTime)){
            throw new FileOperationException(FileErrorResult.SHARE_NOT_EXIST_ERROR);
        }

        UserInfo userInfo = new UserInfo();
        userInfo.setShareSourceUserInfo(user);

        ShareInfo shareInfo = new ShareInfo();
        shareInfo.setPartFieldByFileShare(share);
        shareInfo.setUserInfo(userInfo);

        if (getFileList){
            List<TemplateFile> fileList = fileMapper.selectByShareId(
                    user.getUserId(), share.getShareId());
            shareInfo.setSubFileList(fileDatabaseOperation.templateFile2FileInfo(fileList));
        }
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("code", FileSuccessResult.SHARE_EXIST_SUCCESS.getCode());
        resMap.put("share_info", shareInfo);
        return resMap;
    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED,
                    rollbackFor = {Exception.class})
    public Map<String, Object> shareFileList(Map<String, String> dataMap) {
        // 第二请求: 获取分享文件的相关信息
        String password = dataMap.get("password");
        Integer shareId = Integer.parseInt(dataMap.get("share_id"));
        FileShare share = shareMapper.selectById(shareId);
        if (share == null)
            throw new FileOperationException(FileErrorResult.SHARE_NOT_EXIST_ERROR);

//        System.out.println(password + " " + share.getPassword() + " " + CodeUtil.base64Decode(share.getPassword()));
        if (!password.equals(CodeUtil.base64Decode(share.getPassword())))
            throw new FileOperationException(FileErrorResult.SHARE_PASSWORD_ERROR);

        Integer userId = Integer.parseInt(dataMap.get("src_user_id"));
        List<FileShareItem> shareItemList = shareItemMapper.selectByShareId(userId, shareId);
        List<Long> fileIdList = new ArrayList<>();
        for (FileShareItem item: shareItemList){
            fileIdList.add(item.getFileId());
        }

        List<TemplateFile> shareFileList = fileMapper.selectBatchByFileId(userId, fileIdList);
        List<FileInfo> fileInfoList = fileDatabaseOperation.templateFile2FileInfo(shareFileList);
        String[] keys = new String[]{"code", "file_list"};
        Object[] values = new Object[]{FileSuccessResult.SHARE_FILE_LIST_SUCCESS.getCode(),
                                        fileInfoList};
        return ResultUtil.resultMap(keys, values);
    }

    /**
     *  检测分享者与获取者是否是同一人
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Map<String, String> saveSharedFileCheck(Map<String, String> dataMap) {
        int srcUserId = Integer.parseInt(dataMap.get("src_user_id"));
        int destUserId = Integer.parseInt(dataMap.get("dest_user_id"));
        if (srcUserId == destUserId)
            throw new FileOperationException(FileErrorResult.SHARE_USER_ERROR);

        if (userMapper.selectByUserId(destUserId) == null)
            throw new GenericExcetion(GenericErrorResult.ACCESS_DENIED_ERROR);

        // 被分享文件是否与指定share_id的分享项一致
        List<Long> fileIdList = CodeUtil.string2List(dataMap.get("file_id"), Long.class);

        if (fileIdList.size() == 0)
            throw new FileOperationException(FileErrorResult.SHARE_NOT_EXIST_ERROR);

        dataMap.put("file_id", CodeUtil.object2String(fileIdList));
        return dataMap;
    }

    /**
     *  指定用户的所有分享项
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Map<String, Object> shareInfoList(Integer userId){
        List<FileShare> shareList = shareMapper.selectByUserId(userId);
        List<ShareInfo> shareInfoList = new ArrayList<>();
        for (FileShare share: shareList){
            ShareInfo shareInfo = new ShareInfo();
            shareInfo.setPartFieldByFileShare(share);
            shareInfoList.add(shareInfo);
        }
        System.out.println(shareInfoList);
        String[] keys = new String[]{"code", "share_info_list"};
        Object[] values = new Object[]{FileSuccessResult.SHARE_INFO_LIST_SUCCESS.getCode(), shareInfoList};
        return ResultUtil.resultMap(keys, values);
    }

    /**
     *  延长指定shareId的分享项的有效期
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED,
                    rollbackFor = {Exception.class})
    public Map<String, Object> extendSharedInfoLife(Map<String, String> dataMap){
        int extLife = Integer.parseInt(dataMap.get("ext_life"));
        Map<String, Object> shareInfoMap = (Map<String, Object>) CodeUtil.string2Object(dataMap.get("share_info"));
        // 反射设置值
        ShareInfo shareInfo = CodeUtil.map2Object(shareInfoMap, ShareInfo.class);
        FileShare fileShare = new FileShare();
        if (fileShare == null)
            throw new GenericExcetion(GenericErrorResult.DATA_CODE_ERROR);
        fileShare.setPartFieldByShareInfo(shareInfo);

        fileShare.setExpireTime(fileShare.getExpireTime().plusDays(extLife));
        if (shareMapper.updateById(fileShare) != 1)
            throw new FileOperationException(FileErrorResult.SHARE_UPDATE_ERROR);

        String[] keys = {"code", "expire_time"};
        Object[] values = {FileSuccessResult.SHARE_UPDATE_SUCCESS.getCode(),
                           fileShare.getExpireTime().toString()};
        return ResultUtil.resultMap(keys, values);
    }

    /**
     *  取消已经指定分享项
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED,
                    rollbackFor = {Exception.class})
    public String cancelSharedStatus(Map<String, String> dataMap) {
        Integer srcUserId = Integer.parseInt(dataMap.get("src_user_id"));
        List<Integer> shareIdList = CodeUtil.string2List(dataMap.get("share_id"), Integer.class);
        System.out.println(shareIdList + " " + srcUserId);
        shareItemMapper.deleteBatchByShareId(srcUserId, shareIdList);
        shareMapper.deleteBatchIds(shareIdList);
        return FileSuccessResult.SHARE_CANCEL_SUCCESS.getCode();
    }
}

